package cn.edu.sjtu.se.dslab.rhapsody.parse;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.dom4j.QName;

import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.helper.ApplicationContextHelpler;
import cn.edu.sjtu.se.dslab.project.BusZone;
import cn.edu.sjtu.se.dslab.project.DisplayZone;
import cn.edu.sjtu.se.dslab.project.EntityZone;
import cn.edu.sjtu.se.dslab.rhapsody.entity.BusAgent;
import cn.edu.sjtu.se.dslab.rhapsody.entity.DataZone;
import cn.edu.sjtu.se.dslab.rhapsody.entity.DisplayView;
import cn.edu.sjtu.se.dslab.rhapsody.entity.Event;
import cn.edu.sjtu.se.dslab.service.IDataTypeService;
import cn.edu.sjtu.se.dslab.service.IProjectService;

/**
 * xmi document 用于解析xmi文件，提供获取对应元素的内容
 * @author thinker
 *
 */

public class XmiDocument {
	private static final Logger logger = Logger.getLogger(XmiDocument.class);
	
	private IDataTypeService dataTypeService;
	
	/**
	 * xmiBean
	 */
	private XmiBean xmiBean;
	
	public XmiDocument(String xmiFilePath){
		xmiBean = new XmiBean(xmiFilePath);
		dataTypeService = (IDataTypeService)ApplicationContextHelpler.getBean("dataTypeService");
	}
	
	/**
	 * 根据名字获取UmlModel元素
	 * @param name Uml:Model的名字
	 * @return
	 */
	public UmlModel getUmlModel(String name){
		return xmiBean.getUmlModel(name);
	}
	
	/**
	 * 在对应的UmlModel元素下根据名字获取UmlPackage元素
	 * @param umlModelName  UmlModel的名字
	 * @param packageName   UmlPackage的名字
	 * @return
	 */
	public XmiComposite getUmlPackage(String umlModelName, String packageName){
		UmlModel model = getUmlModel(umlModelName);
		if (null == model) return null;
		return model.getUmlPackage(packageName);
	}
	
	/**
	 * 根据umlType的类型和名称获取对应的元素
	 * @param umlType  即xmiType
	 * @param name  该元素的name属性
	 * @return
	 */
	public XmiType getUmlType(QName umlType, String name){
		Map<String, XmiType> typeMap = xmiBean.getInfoMap().get(umlType.getQualifiedName());
		if (typeMap == null) return null;
		XmiType xType = typeMap.get(name);
		return xType;
	}
	
	/**
	 * 根据ID获取对应的元素
	 * @param xmiId
	 * @return
	 */
	public XmiType getXmiType(String xmiId){
		return xmiBean.getIdMap().get(xmiId);
	}
	
	/**
	 * 得到所有的标注类型
	 * @param typeName 标注类型名称
	 * @return
	 */
	public List<ProfileType> getProfileType(String typeName){
		List<ProfileType> pts = new ArrayList<ProfileType>();
		for (ProfileType pt : xmiBean.getProfileTypes()){
			if (pt.getLabel().equals(typeName)){
				pts.add(pt);
			}
		}
		return pts;
	}
	
	/**
	 * 根据property的名字和属性获取对应的标注类型
	 * @param typeName
	 * @param propertyName 标注类型名称
	 * @param propertyValue
	 * @return
	 */
	public ProfileType getProfileType(String typeName, String propertyName, String propertyValue){
		for(ProfileType pt : getProfileType(typeName)){
			Map<String, String> properties = pt.getProperties();
			String s = properties.get(propertyName);
			if (s != null && s.equals(propertyValue))
				return pt;
		}
		return null;
	}

	public XmiBean getXmiBean() {
		return xmiBean;
	}

	public void setXmiBean(XmiBean xmiBean) {
		this.xmiBean = xmiBean;
	}
	
	/**
	 * 获取显示数据区
	 * @return
	 */
	public List<DisplayZone> getDisplayZones() {
		List<DisplayZone> displayZones = new ArrayList<DisplayZone>();
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_DATAZONE
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			if (prop.get(XmiConst.A_ZONE_TYPE)==null || !prop.get(XmiConst.A_ZONE_TYPE).equals(XmiConst.ZONE_TYPE_DISPLAY) ) continue;
			//查找id和baseProperty相等的ownAttribute标签
			XmiType ownedAttribute = getXmiType(prop.get(XmiConst.A_BASE_PROPERTY));
			if (!ownedAttribute.isComposite()) {
				XmiUnit xu = (XmiUnit) ownedAttribute;
				Map<String, String> xuprops = xu.getProperties();
				DisplayZone displayZone = new DisplayZone();
				displayZone.setName(ownedAttribute.getName());
				
				logger.info(ownedAttribute.getName());
				
				displayZone.setSize(Integer.parseInt(prop.get(XmiConst.A_SIZE)));
				//获取ownAttribute的type属性，查找functional:domainEntity中base_Class与此匹配的类型
				//也有可能是基本类型，那么直接查找数据库即可
				
				
				String entityUri = prop.get(XmiConst.A_ENTITYURI);
				if (entityUri != null && entityUri != ""){
					logger.info("-----------------------" + entityUri);
					displayZone.setEntityUri(prop.get(XmiConst.A_ENTITYURI));
				}else{
					//获取ownAttribute的type属性，查找functional:domainEntity中base_Class与此匹配的类型
					String type = xuprops.get(XmiConst.A_TYPE);
					if (type!= null){
						logger.info("---------------------" + type);
						DomainEntity dateType = dataTypeService.getDataTypeByXmiId(type);
						if (dateType!=null ) {
							logger.info("-------------------------" + dateType.getUri());
							displayZone.setEntityUri(dateType.getUri());
						}
					}
				}
//				String type = xuprops.get(XmiConst.A_TYPE);
//				logger.info(type);
//				DomainEntity dateType = dataTypeService.getDataTypeByXmiId(type);
//				if (dateType!=null ) {
//					displayZone.setEntityUri(dateType.getUri());
//				}
//				else{
//					ProfileType domainEntity = getProfileType(XmiConst.L_FUNCTIONAL_DOMAINENTITY.getQualifiedName(), XmiConst.A_BASE_CLASS, type);
//					displayZone.setEntityUri(domainEntity.getProperties().get(XmiConst.A_ENTITYURI)); //获取这个entity的URI
//				}
				displayZones.add(displayZone);
			}
		}
		return displayZones;
	}
	
	public List<Event> getControlResponses() {
		List<Event> events = new ArrayList<Event>();
		
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_EVENTRESPONSER
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			//if (prop.get(XmiConst.A_ZONE_TYPE)==null || !prop.get(XmiConst.A_ZONE_TYPE).equals("display")) continue;
//			for (Entry<String, String> en: prop.entrySet()){
//				System.out.println("\t" + en.getKey() + "====" +en.getValue());
//			}
			XmiType xt = getXmiType(prop.get(XmiConst.A_BASE_OPERATION));
			if (!xt.isComposite()) {
				XmiUnit xu = (XmiUnit) xt;
				Map<String, String> xuprops = xu.getProperties();
				Event event = new Event();
				event.setName(xu.getName());
				//获取class属性，根据ID获取属性
				//String c = xuprops.get(XmiConst.A_CLASS);
				//event.setClassName(getXmiType(c).getName());
				event.setPageUri(prop.get(XmiConst.A_PAGEURI));
				event.setEventUri(prop.get(XmiConst.A_EVENTURI));
				event.setVisibility(xuprops.get(XmiConst.A_VISIBILITY));
				events.add(event);
			}
		}
		return events;
	}
	
	public List<BusAgent> getBusAgents(){
		List<BusAgent> agents = new ArrayList<BusAgent>();
		
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_BUSINTERACTIONAGENT
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			//解析所有的总线数据区
			BusAgent agent = new BusAgent();
			String busZone = prop.get(XmiConst.A_DATAZONES);
			agent.setBusZone(busZone);
			
			//解析所有的外部系统
			String outerSystem = prop.get(XmiConst.A_OUTERSYSTEMURI);
			agent.setOuterSystem(outerSystem);
			//频率，暂时未使用
			agent.setFrequency(Integer.parseInt(prop.get(XmiConst.A_FREQUENCY)));
			//总线通信函数
			XmiType xt = getXmiType(prop.get(XmiConst.A_BASE_OPERATION));
			if (!xt.isComposite()) {	
				XmiUnit xu = (XmiUnit) xt;
				Map<String, String> xuprops = xu.getProperties();
				agent.setName(xuprops.get(XmiConst.A_NAME));
				//Event event = new Event();
				//event.setName(xuprops.get(XmiConst.A_NAME));
				///event.setVisibility(xuprops.get(XmiConst.A_VISIBILITY));
				//event.setClassName(getXmiType(xuprops.get(XmiConst.A_CLASS)).getName());
				//agent.setReadProcessingEvent(event);
				agents.add(agent);
			}
		}
		return agents;
	}
	
	public List<DisplayView> getDisplayAgents() {
		List<DisplayView> agents = new ArrayList<DisplayView>();
		
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_INFORMATIONDISPLAYAGENT
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			DisplayView agent = new DisplayView();
			//显示数据区
			String dataZones = prop.get(XmiConst.A_DATAZONES);
			if (dataZones != null){
				String[] datazoneArray = dataZones.split(";");
				agent.setDataZones( Arrays.asList(datazoneArray));
			}
			//页面的URI
			agent.setPageUri(prop.get(XmiConst.A_PAGEURI));
			//响应函数
			XmiType xt = getXmiType(prop.get(XmiConst.A_BASE_OPERATION));
			if (!xt.isComposite()) {
				XmiUnit xu = (XmiUnit) xt;
				Map<String, String> xuprops = xu.getProperties();
				Event event = new Event();
				event.setName(xuprops.get(XmiConst.A_NAME));
				event.setVisibility(xuprops.get(XmiConst.A_VISIBILITY));
				event.setClassName(getXmiType(xuprops.get(XmiConst.A_CLASS)).getName());
				agent.setEvent(event);
				agents.add(agent);
			}
		}
		return agents;
	}
	
	/**
	 * 获取实体数据区, 需要调用service函数添加到数据库中
	 * @return
	 */
	public List<EntityZone> getEntityZones() {
		List<EntityZone> entityZones = new ArrayList<EntityZone>();
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_DATAZONE
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			if (prop.get(XmiConst.A_ZONE_TYPE)==null || !prop.get(XmiConst.A_ZONE_TYPE).equals(XmiConst.ZONE_TYPE_DATA_ENTITY) ) continue;
			//查找id和baseProperty相等的ownAttribute标签
			XmiType ownedAttribute = getXmiType(prop.get(XmiConst.A_BASE_PROPERTY));
			if (!ownedAttribute.isComposite()) {
				XmiUnit xu = (XmiUnit) ownedAttribute;
				Map<String, String> xuprops = xu.getProperties();

				EntityZone entityZone = new EntityZone();
				entityZone.setName(ownedAttribute.getName());
				logger.info(ownedAttribute.getName());
				entityZone.setSize(Integer.parseInt(prop.get(XmiConst.A_SIZE)));
				
				String entityUri = prop.get(XmiConst.A_ENTITYURI);
				if (entityUri != null && entityUri != ""){
					logger.info("-----------------------" + entityUri);
					entityZone.setEntityUri(entityUri);
				}else{
					//获取ownAttribute的type属性，查找functional:domainEntity中base_Class与此匹配的类型
					String type = xuprops.get(XmiConst.A_TYPE);
					if (type!= null){
						logger.info("---------------------" + type);
						DomainEntity dateType = dataTypeService.getDataTypeByXmiId(type);
						if (dateType!=null ) {
							logger.info("-------------------------" + dateType.getUri());
							entityZone.setEntityUri(dateType.getUri());
						}
					}
					//ProfileType domainEntity = getProfileType(XmiConst.L_FUNCTIONAL_DOMAINENTITY.getQualifiedName(), XmiConst.A_BASE_CLASS, type);
					//entityZone.setEntityUri(domainEntity.getProperties().get(XmiConst.A_ENTITYURI)); //获取这个entity的URI
				}
				entityZones.add(entityZone);
			}
		}
		return entityZones;
	}
	
	/**
	 * 获取总线数据区
	 * @return
	 */
	public List<BusZone> getBusZones() {
		List<BusZone> busZones = new ArrayList<BusZone>();
		for (ProfileType pt : getProfileType(XmiConst.L_FUNCTIONAL_DATAZONE
				.getQualifiedName())) {
			Map<String, String> prop = pt.getProperties();
			if (prop.get(XmiConst.A_ZONE_TYPE)==null || !prop.get(XmiConst.A_ZONE_TYPE).equals(XmiConst.ZONE_TYPE_BUS) ) continue;
			
			String entityUris = prop.get(XmiConst.A_ENTITYURI);
			if (entityUris!=null){
				String[] entityUriArray = entityUris.split(";");
				for (String uri : entityUriArray){
					logger.info(uri);
				}
			}
			//查找id和baseProperty相等的ownAttribute标签
			XmiType ownedAttribute = getXmiType(prop.get(XmiConst.A_BASE_PROPERTY));
			if (!ownedAttribute.isComposite()) {
				XmiUnit xu = (XmiUnit) ownedAttribute;
				BusZone busZone = new BusZone();
				busZone.setName(ownedAttribute.getName());
				busZones.add(busZone);
			}
		}
		return busZones;
	}
	
	
}
